package com.bsoft.client.proxy;

import com.bsoft.client.common.RequestMetadata;
import com.bsoft.client.transport.RpcTransportFactory;
import com.bsoft.core.common.RpcRequest;
import com.bsoft.core.common.RpcResponse;
import com.bsoft.core.protocol.MessageHeader;
import com.bsoft.core.protocol.MessageProtocol;
import com.bsoft.core.serialization.SerializationType;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 通过CGLIB，为接口生成代理类
 */
public class CGlibRpcProxy implements RpcProxy{
    @Override
    public <T> T proxyInterface(RequestMetadata metadata, Class<T> clazz) {
        Enhancer enhancer = new Enhancer();
        if (clazz.isInterface()) {
            enhancer.setInterfaces(new Class[]{clazz});
        }else{
            enhancer.setSuperclass(clazz);
        }
        enhancer.setCallback(new CGlibProxyInterceptor(clazz, metadata));
        return (T)enhancer.create();
    }


    public class CGlibProxyInterceptor implements MethodInterceptor{
        private Class<?> clazz;
        private String address;
        private int port;
        private SerializationType serializationType;

        public CGlibProxyInterceptor(Class<?> clazz, RequestMetadata metadata) {
            this.clazz = clazz;
            this.address = metadata.getAddress();
            this.port = metadata.getPort();
            this.serializationType = metadata.getSerializationType();
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            //组装消息体
            RpcRequest message = new RpcRequest();
            message.setServiceName(this.clazz.getName());
            message.setMethodName(method.getName());
            message.setParameterTypes(method.getParameterTypes());
            message.setParameters(objects);

            // 组装协议
            MessageProtocol<RpcRequest> protocol = new MessageProtocol<>();
            protocol.setBody(message);
            MessageHeader header = MessageHeader.build(serializationType.name());
            protocol.setHeader(header);

            // 组装元数据
            RequestMetadata metadata = RequestMetadata.builder()
                    .address(address)
                    .port(port)
                    .protocol(protocol)
                    .build();
            MessageProtocol<RpcResponse> response = RpcTransportFactory.getDefaultTransportInstance().send(metadata);
            return response.getBody().getData();
        }
    }
}
